package geometrie;
/**
 * Cet class a tout les méthodes et attributs nécessaires pour faire une matrice de transformation.  
 * 
 */
public class Transformation {
	/**
	 * La matrice de transformation.
	 */
	private Matrice matrice = new Matrice(4,4);
	/**
	 * Constructeur vide.
	 */
	public Transformation(){}
	/**
	 * Constructeur d'une Transformation à partir d'une matrice
	 */
	
	public Transformation(Matrice m){
		matrice = m;
	}
	
	/**
	 * Fait la matrice de transformation d'une traslation (tx,ty,tz)
	 * @param tx Translation dans x
	 * @param ty Translation dans y
	 * @param tz Translation dans z
	 * @return un objet Transformation avec une matrice de translation
	 */
	public static Transformation translation(double tx, double ty, double tz) {
		
		Matrice m = Transformation.identite().getMatrice();
		m.setAt(0,3,tx);
		m.setAt(1,3,ty);
		m.setAt(2,3,tz);
		return new Transformation(m);
	}
	/**
	 * Fait la matrice identité de 4x4
	 * @return Un objet Transformation avec une matrice identité.
	 */
	public static Transformation identite() {
		Matrice m = new Matrice(4,4);
		m.setAt(0, 0, 1);
		m.setAt(1, 1, 1);
		m.setAt(2, 2, 1);
		m.setAt(3, 3, 1);	
		return new Transformation(m);
	}
	/**
	 * Fait la multiplication de tr1 et tr2
	 * @param tr1 La Transformation à faire à la fin
	 * @param tr2 La Transformation à faire au début
	 * @return Un objet Transformation avec la matrice résultant
	 */
	public static Transformation compose(Transformation tr1, Transformation tr2) {
		Matrice m = new Matrice(tr1.getMatrice().getTailleL(),tr2.getMatrice().getTailleC());;
		try {
			//Obtenir la multiplicacion de la Matrice avec le Methode
			//Static de la Classe Matrice
			m= Matrice.multMatrice(tr1.getMatrice(), tr2.getMatrice());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new Transformation(m);
	}
	/**
	 * Fait la rotation autour d'une axe
	 * @param axe Le point sur lequel tourne.
	 * @param angle L'angle de rotation
	 * @return Un objet Transformation avec la matrice résultant 
	 */
	public static Transformation rotation(Point axe, double angle) {
		Matrice matrice = new Matrice(4,4);
		double c = Math.cos(angle);
		double s = Math.sin(angle);
		double k = 1-c;
		matrice.setAt(0,0,k*axe.getXCartesien()*axe.getXCartesien()+c);
		matrice.setAt(0,1,k*axe.getYCartesien()*axe.getXCartesien()-s*axe.getZCartesien());
		matrice.setAt(0,2,k*axe.getZCartesien()*axe.getXCartesien()+s*axe.getYCartesien());
		matrice.setAt(1,0,k*axe.getYCartesien()*axe.getXCartesien()+s*axe.getZCartesien());
		matrice.setAt(1,1,k*axe.getYCartesien()*axe.getYCartesien()+c);
		matrice.setAt(1,2,k*axe.getZCartesien()*axe.getYCartesien()-s*axe.getXCartesien());
		matrice.setAt(2,0,k*axe.getXCartesien()*axe.getZCartesien()-s*axe.getYCartesien());
		matrice.setAt(2,1,k*axe.getYCartesien()*axe.getZCartesien()+s*axe.getXCartesien());
		matrice.setAt(2,2,k*axe.getZCartesien()*axe.getZCartesien()+c);
		matrice.setAt(3,3,1);
		return new Transformation(matrice);
	}
	/**
	 * Rotation autour d'axe X
	 * @param angle L'angle de rotation
	 * @return Un objet Transformation avec la matrice résultant
	 */
	public static Transformation rotationX(double angle) {
		Matrice matrice = new Matrice(4,4);
		double c = Math.cos(angle);
		double s = Math.sin(angle);
		matrice.setAt(0,0,1);
		matrice.setAt(1,1,c);
		matrice.setAt(1,2,-s);
		matrice.setAt(2,1,s);
		matrice.setAt(2,1,c);
		matrice.setAt(3,3,1);		
		return new Transformation(matrice);
	}
	/**
	 * Rotation autour d'axe Y
	 * @param angle L'angle de rotation
	 * @return Un objet Transformation avec la matrice résultant
	 */
	public static Transformation rotationY(double angle) {
		Matrice matrice = new Matrice(4,4);
		double c = Math.cos(angle);
		double s = Math.sin(angle);
		matrice.setAt(0,0,c);
		matrice.setAt(0,2,s);
		matrice.setAt(1,2,1);
		matrice.setAt(2,0,-s);
		matrice.setAt(2,2,c);
		matrice.setAt(3,3,1);	
		return new Transformation(matrice);
	}
	/**
	 * Rotation autour d'axe Z
	 * @param angle L'angle de rotation
	 * @return Un objet Transformation avec la matrice résultant
	 */
	public static Transformation rotationZ(double angle) {
		Matrice matrice = new Matrice(4,4);
		double c = Math.cos(angle);
		double s = Math.sin(angle);
		matrice.setAt(0,0,c);
		matrice.setAt(0,1,-s);
		matrice.setAt(1,0,s);
		matrice.setAt(1,1,c);
		matrice.setAt(2,2,1);
		matrice.setAt(3,3,1);		
		return new Transformation(matrice);
	}
	/**
	 * Pour obtenir la Matrice
	 * @return La matrice du objet Transformation
	 */
	public Matrice getMatrice(){
		return matrice;
	}
	
	public static Transformation inverse(Matrice m){
		Matrice matrice = new Matrice(4,4);
		//T
		Matrice t = new Matrice(3,1);
		for(int i = 0; i < 3; i++)
			t.setAt(i,0,m.getAt(i,3));

		try {
			//R Inverse
			Matrice rInv = Matrice.inverse(new Matrice(3,3,m.getMatrice(3,3)));
			//- rInv * T
			Matrice aux = Matrice.multMatrice(Matrice.scalaire(rInv, -1), t);
			//Cree Matrice Inverse pour la Transformation
			for(int i = 0; i < 3;i++)
				for(int j = 0; j < 3;j++)
					matrice.setAt(i,j,rInv.getAt(i,j));
			for(int i = 0; i < 3; i++)
				matrice.setAt(i,3,aux.getAt(i,0));
			matrice.setAt(3,3,1);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}			
		
		return new Transformation(matrice);
	}
	
	public String toString(){
		return matrice.toString();
	}
}

